home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / test / lib / cb.c < prev    next >
C/C++ Source or Header  |  1992-11-23  |  17KB  |  431 lines

  1. /*
  2.  
  3.     This program is an example that uses the capabilities of Multiple
  4.     Stream C.  It uses the 'nextinput' function and reads its asynchronous
  5.     events rather than using signals.
  6.  
  7.     The program simulates a one channel Citizens Band Radio (CB).  When
  8.     someone logs-on, they are asked for a handle to identify themselves.
  9.     Then everyone signed-on the CB is told that a new user is on.  When
  10.     someone types a message, it is broadcast to everyone on the CB.  Each
  11.     message that is sent is proceeded with the users identification.  There
  12.     are several commands; each begins with a slash (/).  For a list of the
  13.     available commands, type "/HELP".  To log-off, you type the command
  14.     "/BYE".  If the processor is going to go down for maintenance, all the
  15.     users are asked to relogon.
  16.  
  17.     This is basically the same program as in the Multi Stream C Document,
  18.     modified by Dan Leichtenschlag to increase efficiency and to
  19.     demonstrate GEnie specific routines used by Third party authors writing
  20.     Multi stream C applications.  Most obvious is the table of users and
  21.     using fileno(fp) to index into the table rather than searching for a
  22.     file pointer each time.  Other modifications recommended for GEnie
  23.     authors are setting the timeout for streams, and redirecting stdout and
  24.     stderr to files rather than the bit bucket (default for stdout in Multi
  25.     Stream mode).  It also uses the preferred style of having a simple
  26.     processing loop and calling functions for each event rather than
  27.     stuffing all the code into the switch statement like the example.
  28.  
  29.     There are 3 routines provided by GEnie that must be called so GEnie can
  30.     keep track of who is in the game.  They are:
  31.  
  32.     getuser(fp) - called for each user that is allowed in the game.
  33.     touser(fp)  - called to send user back to GEnie.
  34.     delrt()     - called just before game terminates, Game is 'down'.
  35.  
  36.     The getuser and touser routines need the file pointer for that user
  37.     passed so the user can be identified.  getuser returns a character
  38.     pointer to the users U#.  This should be saved by the caller and
  39.     used to uniquely identify users for a database key id needed.
  40.  
  41.     To Compile: cc +v l=game.lib o=cb
  42.  
  43.     GAME.LIB is a library provided to GEnie Authors.
  44. */
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <fcntl.h>
  49. #include <ioctl.h>
  50. #include <string.h>
  51. #include <ctype.h>
  52. #include <time.h>
  53. #include <signal.h>
  54. #include <nextin.h>
  55. #include <mk3c.h>
  56.  
  57. #define BUFFER_SIZE 512
  58. #define MAX_USERS 100              /* Max number of users on CB */
  59. #define HANDLE_LEN 16+1           /* Max length of handle      */
  60. #define USERID_LEN 7+1              /* 7 chars null terminated   */
  61.  
  62. /* Automata States */
  63. #define LOGON     0              /* Ready to receive log-on   */
  64. #define HANDLE     1              /* Requesting handle           */
  65. #define IDLE     2              /* Term ok to receive msgs.  */
  66. #define LOGOFF     3              /* Term is logging off       */
  67. #define NO_ECHO  4              /* Term does not want echo   */
  68.  
  69. int number_of_users;              /* number of users logged on */
  70. int MAX_ON;                  /* highest index so far      */
  71.  
  72. void allow_logon();                       /* functions called in this  */
  73. void broadcast();                         /* source module             */
  74. void logoff();
  75. void comm_down();
  76. void udata();
  77. void uconnect();
  78. void ulinedrop();
  79. void ubreak();
  80. void uinitialize();
  81. void udisconnect();
  82. void ubreak();
  83. void utimeout();
  84. char *getuser();
  85.  
  86. extern void sig_handler();                /* GEnie provided routine    */
  87.  
  88. struct {                  /* user table            */
  89.     FILE *fp;
  90.     int  state;
  91.     char handle[HANDLE_LEN];
  92.     char uid[USERID_LEN];
  93.     int echo;
  94. } user[MAX_USERS];
  95.  
  96. char buffer[BUFFER_SIZE];          /* input buffer           */
  97. char string[BUFFER_SIZE+81];          /* output buffer           */
  98. char helpmsg[350];              /* help message buffer       */
  99.  
  100. /************************************************************************
  101. * main()                                                                *
  102. *         main program and main processing loop            *
  103. ************************************************************************/
  104. main ()
  105. {
  106.   struct next *np;              /* pointer for nextinput     */
  107.   int index;                  /* index into user table     */
  108.  
  109.   uinitialize();                          /* initialization routine    */
  110.  
  111.   while (TRUE) {                          /* wait for 60 secs, 1 min   */
  112.     np = nextinput(60, 0);                /* for nextimput to return   */
  113.  
  114.     if (np->file_pointer)
  115.     index = fileno(np->file_pointer);     /* fileno is index into aray */
  116.     else
  117.     index = 0;
  118.     /*
  119.     printf("fp %08lx index %d status %d\n", np->file_pointer, index, np->status);
  120.     */
  121.  
  122.     switch (np->status) {                 /* what did nextinput return?*/
  123.  
  124.       case S_DATA:              /* there's data, call udata  */
  125.     udata(index);                     /* pass index into table     */
  126.       break;
  127.  
  128.       case S_CONNECT:              /* someone connected           */
  129.     uconnect(np->file_pointer,index); /* pass file pointer & index */
  130.       break;
  131.  
  132.       case S_BREAK:              /* break, acknowledge it     */
  133.     ubreak(index);                    /* pass index into table     */
  134.       break;
  135.  
  136.       case S_DISC:              /* disconnect            */
  137.     udisconnect(index);               /* pass index into table     */
  138.       break;
  139.  
  140.       case S_TIMEOUT:              /* input time out           */
  141.       break;
  142.  
  143.       default:                  /* no activity           */
  144.     delrt();                          /* tell GEnie we're down     */
  145.     comm_down();                      /* just in case, relog users */
  146.     exit();                           /* and terminate             */
  147.       break;
  148.  
  149.     } /* end of switch */
  150.  
  151.   } /* end of while(TRUE) */
  152.  
  153. } /* end of main() routine */
  154.  
  155. /************************************************************************
  156. *  uinitialize()                                                        *
  157. *   called once upon program startup; do any necessary initialization    *
  158. ************************************************************************/
  159. void uinitialize()
  160. {
  161.   int i;
  162.  
  163.  
  164. /*  signal(SIGTERM,comm_down);            /* look for comm shut down   */
  165. /*  signal(SIGMEM,sig_handler);           /* abort and dump on MEM flt */
  166. /*  signal(SIGOVF,sig_handler);           /* abort and dump on OVF flt */
  167.  
  168.   helpmsg[0] = '\0';                      /* build help message        */
  169.   strcat(helpmsg,"These are the available commands:\n\n");
  170.   strcat(helpmsg,"   /bye      - sign-off the CB\n");
  171.   strcat(helpmsg,"   /echo     - toggle echo mode\n");
  172.   strcat(helpmsg,"   /help     - see this list of commands\n");
  173.   strcat(helpmsg,"   /status   - see all users on CB\n");
  174.   strcat(helpmsg,"   /time     - date/time information\n\n");
  175.  
  176.   for (i=0;i<MAX_USERS;++i) {             /* initialize user table     */
  177.     user[i].fp = (FILE *) 0;
  178.     user[i].state = LOGON;
  179.     user[i].echo = FALSE;
  180.     }
  181.   allow_logon();                          /* allow first user to logon */
  182. }
  183.  
  184. /************************************************************************
  185. *  udata()                                                              *
  186. * called when we get a data event, index is pointer into table of users *
  187. ************************************************************************/
  188. void udata(index)
  189. int index;
  190. {
  191.   int i,dtnum;
  192.  
  193.   fgets(buffer,BUFFER_SIZE,user[index].fp);
  194.   switch (user[index].state) {
  195.     case IDLE:                  /* idle state            */
  196.       if (*buffer == '/')  {              /* is this a command?        */
  197.     strupper(buffer);
  198.     if (!strncmp(buffer,"/HELP",4)) {
  199.       fputs(helpmsg,user[index].fp);
  200.       fflush(user[index].fp);
  201.       }
  202.     else if (!strncmp(buffer,"/STATUS",4)) {    /* STATUS request? */
  203.       fprintf(user[index].fp,
  204.           "These are the users on the CB:\n\n");
  205.       fputs("   Handle            U#\n\n",user[index].fp);
  206.       for (i=1; i < MAX_USERS; i++)
  207.         if (user[i].state == IDLE)
  208.           fprintf(user[index].fp,"   %-16.16s  %s\n",
  209.               user[i].handle,user[i].uid);
  210.       fputc('\n',user[index].fp);
  211.       fflush(user[index].fp);
  212.       }
  213.     else if (!strncmp(buffer,"/TIME",4)) {      /* TIME request?   */
  214.       fputs("Today is: ",user[index].fp);
  215.       time(&dtnum);
  216.       fputs(ctime(&dtnum),user[index].fp);
  217.       fflush(user[index].fp);
  218.       }
  219.     else if (!strncmp(buffer,"/ECHO",4)) {      /* ECHO request?   */
  220.       if (user[index].echo)
  221.         user[index].echo = FALSE;
  222.       else
  223.         user[index].echo = TRUE;
  224.       if (user[index].echo)
  225.         fputs("Echo is on.\n",user[index].fp);
  226.       else
  227.         fputs("Echo off.\n",user[index].fp);
  228.       fflush(user[index].fp);
  229.      }
  230.     else if (!strncmp(buffer,"/BYE",4)) {      /* LOG-OFF request? */
  231.       fputs("Logging off, have a nice day.\n",user[index].fp);
  232.       user[index].state = LOGOFF;      /* place in log-off state    */
  233.       sprintf(string,"*<%s> is off\n",user[index].handle);
  234.       broadcast(string,index);        /* tell the world            */
  235.       logoff(index);                  /* log-off the user          */
  236.       }
  237.     else {
  238.       fputs("Invalid command, type /HELP for list of valid commands.\n",
  239.         user[index].fp);
  240.       fflush(user[index].fp);
  241.       }
  242.     }
  243.       else {                  /* send message to everyone  */
  244.     sprintf(string,"<%s> %s",user[index].handle,buffer);
  245.     broadcast(string,index);
  246.       }
  247.       break;
  248.  
  249.     case HANDLE:              /* handle entered state      */
  250.       if (*buffer == '\n') {
  251.     fputs("Please enter a handle: ",user[index].fp);
  252.     fflush(user[index].fp);
  253.     }
  254.       else {
  255.     buffer[strlen(buffer)-1] = '\0';  /* get rid of newline        */
  256.     strncpy(user[index].handle,buffer,HANDLE_LEN);
  257.     sprintf(string,"%s, You are now logged on.  ",user[index].handle);
  258.     strcat(string,"For a list of valid commands, type /HELP\n");
  259.     fputs(string,user[index].fp);
  260.     fflush(user[index].fp);
  261.     sprintf(string,"*<%s> is on\n",user[index].handle);
  262.     broadcast(string,index);          /* tell the world            */
  263.     user[index].state = IDLE;      /* place in idle mode        */
  264.     }
  265.       break;
  266.  
  267.     default:                  /* error, won't happen       */
  268.       fprintf(user[index].fp,
  269.       "Error, took default branch state is  %d\n",user[index].state);
  270.       fflush(user[index].fp);
  271.       break;
  272.   }  /* end switch */
  273. } /* udata() */
  274.  
  275. /************************************************************************
  276. * uconnect()                                                            *
  277. *           called when a user attaches to the program        *
  278. ************************************************************************/
  279. void uconnect(fp,index)
  280. FILE *fp; int index;
  281. {
  282. struct streamio sio;              /* will be filled via ioctl  */
  283. char *uid_ptr;                  /* will point to u#           */
  284. int t;
  285.  
  286.   time(&t);
  287.   fprintf(stdout, "logon\n");
  288.   if (!strncmp("x","EMERGENCYSHUTDOWN",17)) {
  289.     delrt();                              /* tell GEnie we're down     */
  290.     comm_down();                          /* if ^ is PID, log every    */
  291.     fclose(fp);                           /* user off, close this one, */
  292.     exit();                               /* and terminate             */
  293.     }
  294.   if (number_of_users == MAX_USERS) {     /* are we at our limit?      */
  295.     fprintf(fp,"\nSorry, user limit exceeded, try again later\n");
  296.     fclose(fp);                           /* close stream              */
  297.     }
  298.   else {                  /* tell the world of log-on  */
  299.     if (index > MAX_ON)                   /* MAX_ON is the highest     */
  300.       MAX_ON = index;              /* index since pgm startup   */
  301.     user[index].fp = fp;          /* put new user into table   */
  302.     number_of_users++;              /* increment number of users */
  303.     user[index].state = HANDLE;       /* state is request handle   */
  304.     fputs("\n*** Welcome to the mini-CB ***\n\nEnter your handle: ",fp);
  305.     fflush(fp);
  306.     ioctl(fileno(fp),O_GETP,&sio);        /* get I/O parameters        */
  307.     sio.input_time_out = 8*60;          /* input timeout = 8 minutes */
  308.     sio.typeahead_size = 31;          /* set to max buffers        */
  309.     sio.writes_queued = 32;          /* maximum queued writes     */
  310.     ioctl(fileno(fp),O_SETP,&sio);        /* set I/O parameters        */
  311.     uid_ptr = getuser(fp);                /* GEnie routine to log user */
  312.     memcpy(user[index].uid,uid_ptr,8);    /* save users U#             */
  313.     }
  314.   allow_logon();                          /* allow another log-on      */
  315. } /* end uconnect() */
  316.  
  317. /************************************************************************
  318. *  ubreak()                                                             *
  319. *    called when user hits the break key, just acknowledge we got it    *
  320. ************************************************************************/
  321. void ubreak(index)
  322. int index;
  323. {
  324.   fgets(buffer,BUFFER_SIZE,user[index].fp);         /* read the break  */
  325.   fputs("\nBREAK Acknowledged\n",user[index].fp);
  326.   fflush(user[index].fp);
  327. }
  328.  
  329. /************************************************************************
  330. *  disconnect()                                                         *
  331. *         called when we get a disconnect event            *
  332. ************************************************************************/
  333. void udisconnect(index)
  334. int index;
  335. {
  336.    logoff(index);                         /* log-off the user          */
  337.    if (user[index].state != HANDLE) {     /* he never made it on       */
  338.      sprintf(string,"*<%s> has disconnected\n",user[index].handle);
  339.      broadcast(string,index);             /* tell the world            */
  340.      }
  341. }
  342.  
  343. /************************************************************************
  344. *  timeout()                                                            *
  345. *        called when we get a timeout event, log off user        *
  346. ************************************************************************/
  347. void utimeout(index)
  348. int index;
  349. {
  350.    fputs("\nYou have been idle for too long\n",user[index].fp);
  351.    fflush(user[index].fp);
  352.    logoff(index);                         /* log-off the user          */
  353. }
  354.  
  355. /************************************************************************
  356. * allow_logon()                                                         *
  357. *    allow another terminal to log on, terminate if we can't         *
  358. ************************************************************************/
  359. void allow_logon()
  360.   {
  361.     int flags;                  /* flags for open statement  */
  362.                       /* set up flags:           */
  363.     flags  = O_RDWR |              /*     read and write access */
  364.          O_NDELAY |           /*     unroadblocked I/O     */
  365.          O_NO_SIGNAL |          /*     don't give me signals */
  366.          O_NO_DISC;           /*     give U#= on close     */
  367.     if (!(openport(flags, 0)))  {         /* open a port for a log-on  */
  368.       comm_down();                        /* if error, boot everyone   */
  369.       delrt();                            /* tell GEnie we're down     */
  370.       exit();                             /* and terminate             */
  371.       }
  372.   } /* end allow_logon() */
  373.  
  374. /************************************************************************
  375. * logoff()                                                              *
  376. *      relog the user, close the stream. and clear out array     *
  377. ************************************************************************/
  378. void logoff(index)
  379.   int index;
  380.  
  381.   {
  382.     touser(user[index].fp);               /* return user to GEnie      */
  383.     fclose(user[index].fp);               /* close the stream          */
  384.     number_of_users--;              /* decrement number of users */
  385.     user[index].fp = 0;           /* make table entry available*/
  386.     user[index].state = LOGON;          /* put in not connected state*/
  387.   } /* end logoff() */
  388.  
  389. /************************************************************************
  390. * broadcast()                                                           *
  391. *        Broadcast a message to every user online        *
  392. ************************************************************************/
  393. void broadcast(stringy,index)
  394.   char *stringy;
  395.   int index;
  396.  
  397.   {
  398.     int i;
  399.     int save;
  400.  
  401.     save = user[index].state;          /* save this user's state    */
  402.     if (!(user[index].echo))              /* does user want echo?      */
  403.       user[index].state = NO_ECHO;      /* no, change state           */
  404.  
  405.     for( i = 0; i <= MAX_ON; i++)         /* for any users online      */
  406.       if (user[i].state == IDLE)  {       /* if idle user, write msg   */
  407.     fputs(stringy,user[i].fp);
  408.     fflush(user[i].fp);
  409.       }
  410.  
  411.     user[index].state = save;          /* restore user state        */
  412.     } /* end broadcast() */
  413.  
  414. /************************************************************************
  415. * comm_down()                                                           *
  416. * Log off all users.  Called if job is idle or processor is going down. *
  417. ************************************************************************/
  418. void comm_down()
  419. {
  420.     int i;
  421.  
  422.     strcpy(string,
  423.     "<PROCESSOR MESSAGE> Going down for maintainence.  Please relogon.");
  424.     for( i = 0; i <= MAX_ON; i++)         /* for all users online      */
  425.       if (user[i].state != LOGON)  {      /* send message and log-off  */
  426.     fputs(string,user[i].fp);
  427.     logoff(i);
  428.       }
  429. } /* end comm_dowm() */
  430.  
  431.